<template>
  <div class="validate-input-container pb-3">
    <input
      v-if="tag !== 'textarea'"
      type="text"
      class="form-control"
      :class="{'is-invalid' : inputRef.error}"
      id="exampleInputEmail1"
      @blur="validateInput"
      v-model="inputRef.val"
      v-bind="$attrs"
    />
    <textarea
      v-else
      class="form-control"
      :class="{'is-invalid' : inputRef.error}"
      id="exampleInputEmail2"
      @blur="validateInput"
      v-model="inputRef.val"
      v-bind="$attrs"
    />
    <span v-if="inputRef.error" class="invalid-feedback">{{inputRef.message}}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType, reactive, onMounted, computed } from 'vue'
import { emitter } from './ValidateForm.vue'
// 邮箱验证
const emailReg = /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/
interface RuleProp{
  type: 'required' | 'email' | 'minLength' | 'maxLength' | 'custom';
  message: string;
  validator?: () => boolean;
}
export type RulesProp = RuleProp[]
export type tagType = 'input' | 'textarea'
export default defineComponent({
  name: 'validate-input',
  props: {
    rules: {
      type: Array as PropType<RulesProp>
    },
    modelValue: String,
    tag: {
      type: String as PropType<tagType>,
      default: 'input'
    }
  },
  // 不希望组件的根元素继承 attribute，在input上绑定$attrs，根元素上的属性($attrs)就可以绑定到input上
  inheritAttrs: false,
  // v-model实现
  // 1、创建一个modelValue属性
  // 2、提交'update:modelValue'
  setup (props, context) {
    const inputRef = reactive({
      val: computed({
        get: () => props.modelValue || '',
        set: val => {
          context.emit('update:modelValue', val)
        }
      }),
      error: false,
      message: ''
    })
    const validateInput = () => {
      if (props.rules) {
        // every() 方法用于检测数组所有元素是否都符合指定条件
        const allPassd = props.rules.every((rule) => {
          let passed = true
          inputRef.message = rule.message
          switch (rule.type) {
            case 'required':
              passed = (inputRef.val.trim() !== '')
              break
            case 'email':
              passed = emailReg.test(inputRef.val)
              break
            case 'minLength':
              passed = (inputRef.val.trim().length >= 6)
              break
            case 'maxLength':
              passed = (inputRef.val.trim().length < 20)
              break
            case 'custom':
              passed = rule.validator ? rule.validator() : true
              break
            default:
              break
          }
          return passed
        })
        inputRef.error = !allPassd
        return allPassd
      }
      return true
    }
    onMounted(() => {
      emitter.emit('form-item-created', validateInput)
    })

    return {
      inputRef,
      validateInput
    }
  }
})
</script>
